package com.xframe.xdal.core.model;

import com.xframe.xdal.core.constant.DalConstants;
import com.xframe.xdal.core.constant.SqlBuilderConstants;
import com.xframe.xdal.core.model.es.IQueryBuilder;
import com.xframe.xdal.core.model.es.QueryBuilderFactory;
import com.xframe.xdal.core.model.mapping.IColumnMapping;
import com.xframe.xdal.core.model.mapping.ITableInfo;
import com.xframe.xdal.core.model.sqlbuilder.BuilderContext;
import com.xframe.xdal.core.util.StringUtil;
import lombok.AccessLevel;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 功能描述:查询条件组信息
 *
 * @author xufeng
 * @version 1.0
 * @date 2022-09-26
 */
@Data
@Log4j2
public class ConditionValueCollection {


    public ConditionValueCollection getNewConditionValueCollection(boolean isAttrPath){

        ConditionValueCollection conditionValueCollection = new ConditionValueCollection();
        conditionValues.forEach( conditionValue -> {
            if(conditionValue.isAttrPath() == isAttrPath){
                conditionValueCollection.conditionValues.add(conditionValue);
            }
        });
        return conditionValueCollection;
    }

    /**
     * 查询条件对象集合
     */
    @Setter(AccessLevel.NONE)
    private List<ConditionValue> conditionValues = new ArrayList<>();


    /**
     * 按照组名称来分组的查询条件对象
     */
    @Setter(AccessLevel.NONE)
    @Getter(AccessLevel.NONE)
    private Map<String,List<ConditionValue>> conditionValueMap = null;

    /**
     * 添加查询对象
     *
     * @param conditionValue 查询对象
     */
    public void add(ConditionValue conditionValue) {
        conditionValues.add(conditionValue);
    }


    /**
     * 添加查询对象
     *
     * @return Map<String,List<ConditionValue>> 分组后的查询对象
     */
    public Map<String,List<ConditionValue>> getConditionValueMap(){
        if(conditionValueMap == null){
            initConditionValueMap();
        }
        return this.conditionValueMap;
    }
    /**
     * 初始化  groupName 相同的成为一组，之间是OR的关系
     *
     * @return
     */
    private void initConditionValueMap(){
        if(conditionValueMap != null){
            conditionValueMap.clear();
        }
        conditionValueMap = new HashMap<>();
        for(ConditionValue conditionValue : this.conditionValues){
            if(!conditionValueMap.containsKey(conditionValue.getGroupName())){
                conditionValueMap.put(conditionValue.getGroupName(),new ArrayList<>());
            }
            if(conditionValue.getVal() != null && !StringUtil.isEmpty(conditionValue.getVal().toString())) {
                conditionValueMap.get(conditionValue.getGroupName()).add(conditionValue);
            }
        }
    }

    /**
     * 构造where 改where用于非查询的SQL语句
     *
     */
    public void builderWhereByKeyNoQuery(BuilderContext context,ITableInfo tableInfo,String colPlaceholder,
                                  StringBuilder whereBuilder,List<Object> pList){
        //StringBuilder tmpBuilder = new StringBuilder();
        int index = 0;
        // 处理查询条件
//        if(conditionValueMap == null || conditionValueMap.size() == 0){
//            initConditionValueMap();
//        }
        initConditionValueMap();
        for (Map.Entry<String, List<ConditionValue>> next: conditionValueMap.entrySet()) {
            List<ConditionValue> conditionValues = next.getValue();
            StringBuilder tmpBuilder = new StringBuilder();
            tmpBuilder.append(DalConstants.SQL_AND + " (");
            for(ConditionValue conditionValue : next.getValue()){
                if(!conditionValue.isAttrPath()){
                    tmpBuilder.append(buildWhereHelpNoQuery(context,colPlaceholder,tableInfo,conditionValue.getKeyName(),conditionValue));
                }
                if(index + 1 < conditionValues.size()){
                    tmpBuilder.append(DalConstants.SQL_OR);
                }
                pList.add(conditionValue.getVal());
                index++;
            }
            tmpBuilder.append(")");
            if(tmpBuilder.length() > 7){
                whereBuilder.append(tmpBuilder);
            }
        }


    }
    /**
     * 构造where where用于查询的SQL语句
     * 组名称相同的 则是or连接 组与组之间 使用and
     *
     */
    public void builderWhereByKey(BuilderContext context,ITableInfo tableInfo,
                                  String colPlaceholder,StringBuilder whereBuilder,List<Object> pList){
        StringBuilder tmpBuilder = new StringBuilder();
        int index = 0;
        for(ConditionValue conditionValue : this.conditionValues){
            if(!conditionValue.isAttrPath()) {
                tmpBuilder.append(buildWhereHelp(context, colPlaceholder, tableInfo, SqlBuilderConstants.MAINTABELNAME, conditionValue.getKeyName(), conditionValue));

                if (index + 1 < conditionValues.size()) {
                    tmpBuilder.append(DalConstants.SQL_AND);
                }
                if (conditionValue.getOperators() != Operator.IN && conditionValue.getOperators() != Operator.NIN) {
                    pList.add(conditionValue.getVal());
                }
            }
            index++;
        }
        whereBuilder.append(tmpBuilder);
    }

    public void builderWhere(BuilderContext context,ITableInfo tableInfo,
                             Map<String,ITableInfo> refTable,
                             String colPlaceholder, StringBuilder whereBuilder, List<Object> pList){
        // 处理查询条件
//        if(conditionValueMap == null || conditionValueMap.size() == 0){
//            initConditionValueMap();
//        }
        initConditionValueMap();
        for (Map.Entry<String, List<ConditionValue>> next: conditionValueMap.entrySet()) {
            List<ConditionValue> conditionValues = next.getValue();
            StringBuilder tmpBuilder = new StringBuilder();
            tmpBuilder.append(DalConstants.SQL_AND + " (");
            for (int index = 0; index < conditionValues.size(); index++) {
                ConditionValue conditionValue = conditionValues.get(index);
                if(conditionValue.isAttrPath()){
                    // 属性路径
                    String[] paths = conditionValue.getKeyName().split("\\" + SqlBuilderConstants.SP);
                    if(refTable.containsKey(paths[0])){
                        ITableInfo refTableInfo = refTable.get(paths[0]);
                        tmpBuilder.append(buildWhereHelp(context,colPlaceholder,refTableInfo,paths[0],paths[1],conditionValue));
                    }
                }else {
                    tmpBuilder.append(buildWhereHelp(context,colPlaceholder,tableInfo,SqlBuilderConstants.MAINTABELNAME,conditionValue.getKeyName(),conditionValue));
                }
                if(index + 1 < conditionValues.size()){
                    tmpBuilder.append(DalConstants.SQL_OR);
                }
                if(conditionValue.getOperators() != Operator.IN && conditionValue.getOperators() != Operator.NIN) {
                    pList.add(conditionValue.getVal());
                }
            }
            tmpBuilder.append(")");
            if(tmpBuilder.length() > 7){
                whereBuilder.append(tmpBuilder);
            }
        }
    }

    private static String buildWhereHelpNoQuery(BuilderContext context,String placeholder,ITableInfo refTableInfo,String attrName,ConditionValue conditionValue){
        IColumnMapping columnMapping = refTableInfo.findOneByFieldName(attrName);
        if(columnMapping == null){
            return "";
        }
        if(conditionValue.getOperators() == Operator.IN || conditionValue.getOperators() == Operator.NIN){
            return placeholder + context.getNameConvert().toName(columnMapping.getName()) + placeholder +
                    conditionValue.getOperatorsVal() + conditionValue.getVal() + ")";
        }
        return placeholder + context.getNameConvert().toName(columnMapping.getName()) + placeholder +
                conditionValue.getOperatorsVal() + DalConstants.SQL_PLACE_HOlDER;
    }

    private static String buildWhereHelp(BuilderContext context,String placeholder,ITableInfo refTableInfo,String asName,String attrName,ConditionValue conditionValue){
        IColumnMapping columnMapping = refTableInfo.findOneByFieldName(attrName);
        if(columnMapping == null){
            return "";
        }
        if(conditionValue.getOperators() == Operator.IN || conditionValue.getOperators() == Operator.NIN){
            return placeholder + context.getNameConvert().toName(columnMapping.getName()) + placeholder +
                    conditionValue.getOperatorsVal() + conditionValue.getVal() + ")";
        }
        return placeholder + asName + placeholder + SqlBuilderConstants.SP +
                placeholder + context.getNameConvert().toName(columnMapping.getName()) + placeholder +
                conditionValue.getOperatorsVal() + DalConstants.SQL_PLACE_HOlDER;
    }
    /**
     * 添加开始结束日期条件
     *
     * @param name         名称
     * @param startDateStr 开始事件字符串  yyyy-MM-dd
     * @param endDateStr   结束时间字符串  yyyy-MM-dd
     * @throws ParseException 解析异常
     */
    public void addConditionByBegEndDate(String name, String startDateStr, String endDateStr) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date startDateDate = sdf.parse(startDateStr + " 00:00:00");
        Date endDateDate = sdf.parse(endDateStr + " 23:59:59");
        java.sql.Timestamp startDateTs = new java.sql.Timestamp(startDateDate.getTime());
        java.sql.Timestamp endDateTs = new java.sql.Timestamp(endDateDate.getTime());
        conditionValues.add(new ConditionValue(name, Operator.GE, startDateTs));
        conditionValues.add(new ConditionValue(name, Operator.LE, endDateTs));
    }
    /**
     * 添加In操作符
     *
     * @param name         名称
     * @param paramList 值列表
     * @param isString 是否添加单引号
     */
    public void addConditionByIn(String name,Collection paramList,boolean isString){
        if(paramList == null || paramList.size() == 0){
            return;
        }
        StringBuilder stringBuilder = new StringBuilder();

        paramList.forEach(val ->{
            if(val != null && !StringUtil.isEmpty(val.toString())) {
                if(isString){
                    stringBuilder.append("'" + val + "'" + ",");
                }else {
                    stringBuilder.append(val + ",");
                }
            }
        });
        if(stringBuilder.length() == 0){
            return;
        }
        String vals = stringBuilder.substring(0,stringBuilder.length() - 1);
        conditionValues.add(new ConditionValue(name, Operator.IN, vals));
    }

    /**
     * 添加In操作符
     *
     * @param name         名称
     * @param isString 是否添加单引号
     * @param paramList 值列表
     */
    public void addConditionByIn(String name,boolean isString,Object... paramList){
        if(paramList == null || paramList.length == 0){
            return;
        }
        List<Object> list = new ArrayList<>();
        Collections.addAll(list,paramList);
        addConditionByIn(name,list,isString);
    }


    /**
     * 添加not In操作符
     *
     * @param name         名称
     * @param paramList 值列表
     * @param isString 是否添加单引号
     */
    public void addConditionByNotIn(String name,Collection paramList,boolean isString){
        if(paramList == null || paramList.size() == 0){
            return;
        }
        StringBuilder stringBuilder = new StringBuilder();

        paramList.forEach(val ->{
            if(val != null && !StringUtil.isEmpty(val.toString())) {
                if(isString){
                    stringBuilder.append("'" + val + "'" + ",");
                }else {
                    stringBuilder.append(val + ",");
                }
            }
        });
        if(stringBuilder.length() == 0){
            return;
        }
        String vals = stringBuilder.substring(0,stringBuilder.length() - 1);
        conditionValues.add(new ConditionValue(name, Operator.NIN, vals));
    }

    /**
     * 添加not In操作符
     *
     * @param name         名称
     * @param isString 是否添加单引号
     * @param paramList 值列表
     */
    public void addConditionByNotIn(String name,boolean isString,Object... paramList){
        if(paramList == null || paramList.length == 0){
            return;
        }
        List<Object> list = new ArrayList<>();
        Collections.addAll(list,paramList);
        addConditionByNotIn(name,list,isString);
    }




    private List<ConditionValue> existxNotEQ(List<ConditionValue> conditionValues,List<ConditionValue> conditionValueList){
        List<ConditionValue> notEQcondit = new ArrayList<>();
        for (int index = 0; index < conditionValues.size(); index++) {
            ConditionValue conditionValue = conditionValues.get(index);
            if(conditionValue.getOperators() == Operator.NE
                    || conditionValue.getOperators() == Operator.NIN ||
                    conditionValue.getOperators() == Operator.NLIKE){

                notEQcondit.add(conditionValue);
            }
            else {
                conditionValueList.add(conditionValue);
            }
        }
        return notEQcondit;
    }






    private void createHelp(List<QueryBuilder> queryBuilders,List<ConditionValue> conditionValueList){
        for (int index = 0; index < conditionValueList.size(); index++) {
            ConditionValue conditionValue = conditionValueList.get(index);

            IQueryBuilder queryBuilder = QueryBuilderFactory.create(conditionValue);
            if(queryBuilder == null){
                continue;
            }
            // 构造ES查询条件
            QueryBuilder query = queryBuilder.builder(conditionValue);
            if(query != null){
                queryBuilders.add(query);
            }
        }
    }

    private BoolQueryBuilder boolQueryBuilderHelp(List<ConditionValue> conditionValueList,List<ConditionValue> notEQcondit){
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if(conditionValueList != null && conditionValueList.size() > 0) {
            List<QueryBuilder> should = boolQueryBuilder.should();
            createHelp(should, conditionValueList);
        }
        if(notEQcondit != null && notEQcondit.size() > 0) {
            List<QueryBuilder> mustNot = boolQueryBuilder.mustNot();
            createHelp(mustNot, notEQcondit);
        }
        return boolQueryBuilder;
    }



    public QueryBuilder builderBoolQueryBuilder(){
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if(conditionValues == null || conditionValues.size() == 0){
            return boolQueryBuilder;
        }
        // 处理查询条件
        if(conditionValueMap == null || conditionValueMap.size() == 0){
            initConditionValueMap();
        }
        for (Map.Entry<String, List<ConditionValue>> next: conditionValueMap.entrySet()) {
            List<ConditionValue> conditionValues = next.getValue();
            List<QueryBuilder> must = boolQueryBuilder.must();
            List<ConditionValue> conditionValueList = new ArrayList<>();
            List<ConditionValue> notEQcondit = existxNotEQ(conditionValues,conditionValueList);
            if(notEQcondit != null && notEQcondit.size() > 0){
                // 存在不等于
                must.add(boolQueryBuilderHelp(conditionValueList,notEQcondit));
            }
            else if(conditionValues.size() > 1){
                // 没有不等于 但是数量大于1个条件
                //must.add(boolQueryBuilderHelp(conditionValues,notEQcondit));
                createHelp(boolQueryBuilder.should(),conditionValues);
            }else {
                createHelp(must,conditionValues);
            }
        }

        return boolQueryBuilder;
    }

}
